使用 python argparse: 编写友好的命令行接口

2017-05-07

Python 的 args 和 kwargs 总是感觉对人不太友好,直到 *argparse 模块的出现解救了我!学习 argparse Tutorial 的时候又不小心发现了格式化字符串的函数“str”.format,瞬间,有了一种进城的感觉。
dakang

argparse模块使得编写用户友好的命令行接口非常容易。程序只需定义好它要求的参数,然后argparse将负责如何从sys.argv中解析出这些参数。argparse模块还会自动生成帮助和使用信息并且当用户赋给程序非法的参数时产生错误信息。

首先准备一下基础知识:
arguments即:参数,函数被调用时,必须要知道的一些信息。有时函数需要接收不止一个参数,这么多参数,它如何一一对上号呢?这个对号入座的策略就是Python的参数传递机制。

策略1 - positional arguments: 位置参数

位置参数即:函数和大家声明好了,传给我的第一个参数是梨,第二个参数是枣,第三个参数是西瓜,你们调用我的时候必须按照这个顺序来,出错了我可不负责哦!😝
优点:输入简洁,方便
缺点:参数多时,准确记住顺序困难,输入量也很大。

1
2
3
4
5
# 定义
def subtract(a, b):
return a-b
# 调用
subtract(3,2)

策略2 - keyword arguments: 关键字参数

如果你实在记不住参数的顺序,但你可以记得你参数的名字,那么你可以使用keyword arguments,常常见到Github上别人家的代码充斥着 *args , kwargs 这些天书一般的符号,看得都晕了,但其实,它们虽然写起来比较复杂,但是对于调用者来说却十分方便。使用时,不必记住每个参数的顺序,只需告诉函数我这个参数的名字和值,函数就知道如何对应。如果你觉得输入名字太麻烦,按顺序给参数也可以,兼容位置参数。

1
2
3
4
5
6
# 定义
def subtract(substract_start, substract_end):
return substract_start-substract_end
# 调用: 3-2=?
subtract(3, 2)
subtract(substract_end=2, substract_start=3)

策略3 - optional arguments: 可选参数

实际上,我们常常只会用到函数的一部分参数,如果想要你的函数对别人友好一些,那就得辛苦一下在代码里多写几行了。如果调用者制定了参数的值,那就使用这个值,如果没有,那就使用默认值。

1
2
3
4
5
6
7
# 定义
def subtract(substract_start, substract_end):
return substract_start-substract_end
# 调用: 3-2=?
subtract(3) # 3-1=?
subtract(substract_start=3) # 3-1=?
subtract(substract_end=2, substract_start=3) # 3-2=?

argeparse 使用

需要注意的一点: argparse 用于编写用户交互命令行接口,前面我们说的是函数调用的接口,这一点要清楚。argparse能让你的程序更加友好,更加鲁棒,用户的肆意输入也不会让它崩溃,同时还能提供提示信息,告诉用户如何正确地使用你的程序。
下面我们通过栗子来看看,argparse到底有多方便:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
""" Command-line arg parsing library
Example Usage:
- python learn_argparse.py -h
- python learn_argparse.py "hello"
- python learn_argparse.py "hello" -d 1.66 -f
- python learn_argparse.py "hello" -d 1.66 -f -t clean
"""
import argparse
# =========================
# CPython argparse Example
# =========================
def test():
parser = argparse.ArgumentParser()
# add arguments
parser.add_argument("echo", help="echo the string you use here")
parser.add_argument("-d", "--double", help="double the number you input here", type=float)
parser.add_argument("-f", "--format", help="format the output", action='store_true')
parser.add_argument("-t", "--type", help="output format type", choices=["clean", "math", "string"], default="math")
# parse arguments
args = parser.parse_args()
print(" - {:^15}: {}".format("The string is", args.echo))
if args.double:
if not args.format:
print(" - {:^15}: {}".format("The rst is", 2 * args.double))
else:
if args.type == "clean":
print(" - {:^15}: {}".format("The rst is", 2 * args.double))
elif args.type == "string":
print(" - {:^15}: {}".format("The double of {:>8} is {:>8}", args.double, 2 * args.double))
else:
print(" - {:^15}: {} * {} = {}".format("The exp is", args.double, args.double, 2 * args.double))
if __name__ == '__main__':
test()

例子中涉及了4种参数的使用方法:

1. echo: 位置参数,必须
2. -d: 加'-'表示可选参数,type限定输入类型
3. -f: 标记参数,action=store_true, 输入代表True,不输入代表False,后面不跟其他值
4. -t: 限定参数的选择范围:["clean", "math", "string"]只能是三者之一; 缺省默认值default="math"。  

实例:
input
output